package org.zn.note.jdk.container;

import java.util.*;
import java.util.concurrent.*;

public class JavaContainers {

    private static void testHashMap() {

        // 不同的对象，相同的hashCode
        Object o1 = getNewObject(1);
        Object o2 = getNewObject(1);
        Map map = new HashMap();
        map.put(o1, 123);
        map.put(o2, 456);
        System.out.println(map);
    }

    /**
     * 返回不同的对象，但是有相同hashCode
     *
     * @param hashCode
     * @return
     */
    private static Object getNewObject(final int hashCode) {
        return new Object() {
            @Override
            public int hashCode() {
                return hashCode;
            }
        };
    }

    // 枚举Enum当Key的Map
    private static void testEnumMap() {
        Map<Day, String> map = new EnumMap(Day.class);
        map.put(Day.MONDAY, "星期一");
        map.put(Day.TUESDAY, "星期二");
        Day day = Day.TUESDAY;
        System.out.println("Today is " + map.get(day));
        System.out.println("Today is " + map.get(day));
        // 对应还有EnumSet
        EnumSet enumset = EnumSet.noneOf(Day.class); //创建一个空的Day枚举类型的队列
        System.out.println("Before:" + enumset);
        enumset.add(Day.MONDAY);                  //添加三个元素
        enumset.add(Day.TUESDAY);
        enumset.add(Day.WEDNESDAY);
        System.out.println("After:" + enumset);     //添加元素后状态
        EnumSet enumset2 = EnumSet.allOf(Day.class);
        System.out.println("每一天：" + enumset2);
        EnumSet enumset3 = EnumSet.range(Day.MONDAY, Day.FRIDAY);
        System.out.println("工作日：" + enumset3);
        EnumSet enumset4 = EnumSet.complementOf(enumset3); // 补集
        System.out.println("休息日：" + enumset4);
        EnumSet enumset5 = EnumSet.copyOf(enumset4); // 复制
        System.out.println("休息日：" + enumset5);
        EnumSet enumset6 = EnumSet.copyOf(Arrays.asList(Day.SATURDAY, Day.SATURDAY, Day.SUNDAY)); // 复制
        System.out.println("休息日：" + enumset6);
    }

    /*
    LinkedHashMap  (其实就是HashMap + 双向链表)
    HashMap无序，LinkedHashMap有序
    LinkedHashMap有自己的Entry：Entry<K,V> extends HashMap.Node<K,V>，其实里面就是多了两个指针：
        Entry<K,V> before, after;  -- 指向挨着的Node
    1、构造方法没什么特殊的，就是多了设置 accessOrder
       accessOrder = false(默认) 插入顺序存储； true 访问顺序存储
       当调用get或getOrDefault最后，都会：
       if(accessOrder)  afterNodeAccess(e);  -- 把当前Node“移到最后” （实际的HashMap存储没变）
    2、get(Key)         就是多了上面1中内容
    3、put(Key, Vlaue)  用的HashMap的，没有重写。
                        但是HashMap留了口，就是put后会调用afterNodeInsertion()，HashMap没有实现这个。LinkedHashMap实现了。
    其实就是HashMap，只不过在类中维护了两个指针：
    transient LinkedHashMap.Entry<K,V> head; // The head (eldest) of the doubly linked list.
    transient LinkedHashMap.Entry<K,V> tail; // The tail (youngest) of the doubly linked list.
    在Entry中增加了两个指针：
    Entry<K,V> before, after;
    这样在HashMap存储的基础上，实现了双向链表的功能：其他操作都是维护这4个指针，只有foreach的时候用到了
     */
    private static void testLinkedHashMap() {
        // 第三个参数用于指定accessOrder值
        Map<String, String> linkedHashMap = new LinkedHashMap<>(16, 0.75f, true);
        linkedHashMap.put("name1", "111");
        linkedHashMap.put("name2", "222");
        linkedHashMap.put("name3", "333");
        System.out.println("开始时顺序：");
        Set<Map.Entry<String, String>> set = linkedHashMap.entrySet();
        Iterator<Map.Entry<String, String>> iterator = set.iterator();
        while (iterator.hasNext()) {
            Map.Entry entry = iterator.next();
            String key = (String) entry.getKey();
            String value = (String) entry.getValue();
            System.out.println("key:" + key + ",value:" + value);
        }
        System.out.println("通过get方法，导致key为name1对应的Entry到表尾");
        linkedHashMap.get("name1");
        Set<Map.Entry<String, String>> set2 = linkedHashMap.entrySet();
        Iterator<Map.Entry<String, String>> iterator2 = set2.iterator();
        while (iterator2.hasNext()) {
            Map.Entry entry = iterator2.next();
            String key = (String) entry.getKey();
            String value = (String) entry.getValue();
            System.out.println("key:" + key + ",value:" + value);
        }
    }

    /*
    WeakHashMap
     */
    private static void testWeakHashMap() {
        Map map = new WeakHashMap();
        String key1 = new String("key1");
        String key2 = new String("key2");
        String key3 = new String("key3");
        map.put(key1, "111");
        map.put(key2, "222");
        map.put(key3, "333");
        System.out.printf("WeakHashMap:%s\n", map); // WeakHashMap:{key1=111, key2=222, key3=333}
        key1 = null;
        System.gc();
        System.out.printf("WeakHashMap:%s\n", map); // WeakHashMap:{key2=222, key3=333}
    }

    /*
    TreeMap  对key排序
    要么传一个 Comparator，要么key本身是Comparable的
    有 Comparator 用  comparator.compare((K)k1, (K)k2);
    否则用：((Comparable<? super K>)k1).compareTo((K)k2)
    （就是如果没有Comparator，key还不是Comparable的，会报错ClassCastException）
     */
    private static void testTreeMap() {
        //创建TreeMap对象：
        TreeMap<String, Integer> treeMap = new TreeMap<>();
        System.out.println("初始化后,TreeMap元素个数为：" + treeMap.size());
        //新增元素:
        treeMap.put("hello", 1);
        treeMap.put("world", 2);
        treeMap.put("my", 3);
        treeMap.put("name", 4);
        treeMap.put("is", 5);
        treeMap.put("jiaboyan", 6);
        treeMap.put("i", 7);
        treeMap.put("am", 8);
        treeMap.put("a", 9);
        treeMap.put("developer", 10);
        System.out.println("添加元素后,TreeMap元素个数为：" + treeMap.size());
        //遍历元素：
        Set<Map.Entry<String, Integer>> entrySet = treeMap.entrySet();
        for (Map.Entry<String, Integer> entry : entrySet) {
            String key = entry.getKey();
            Integer value = entry.getValue();
            System.out.println("TreeMap元素的key:" + key + ",value:" + value);
        }
        //获取所有的key：
        Set<String> keySet = treeMap.keySet();
        for (String strKey : keySet) {
            System.out.println("TreeMap集合中的key:" + strKey);
        }
        //获取所有的value:
        Collection<Integer> valueList = treeMap.values();
        for (Integer intValue : valueList) {
            System.out.println("TreeMap集合中的value:" + intValue);
        }
        //获取元素：
        Integer getValue = treeMap.get("jiaboyan");
        String firstKey = treeMap.firstKey(); // 第一个key  -- SortedMap[I]
        String lastKey = treeMap.lastKey(); // 最后一个key  -- SortedMap[I]
        String lowerKey = treeMap.lowerKey("jiaboyan"); // 小于"jiaboyan"的key  -- NavigableMap extends SortedMap
        String ceilingKey = treeMap.ceilingKey("jiaboyan");// 大于等于"jiaboyan"的key  -- NavigableMap extends SortedMap
        SortedMap<String, Integer> sortedMap = treeMap.subMap("a", "my"); // key从"a"到"jiaboyan"的元素 -- SortedMap[I]
        System.out.println((Comparable) new Object()); // ClassCastException
    }

    /*
    ConcurrentHashMap 线程安全的HashMap
    1、分段锁，支持[分段数]的线程并发
    2、put加锁，get不加锁
     */
    private static void testConcurrentHashMap() {
        Map map = new ConcurrentHashMap();
    }

    /*
    线程安全的Key排序
    通过跳表实现（skip list 跳跃列表）
    1、有三种节点 Node, Index, HeadIndex
    2、分层的，横向、纵向都是链表
    3、最下面的层（Level 1）是 Node层，存储数据；上面的层（Level >1）是Index层。
    HeadIndex -------------------------------> Indx
    HeadIndex -------------------------------> Indx --------------------> Indx
    HeadIndex ------------>  Indx -----------> Indx -----------> Indx --> Indx
    Node      -->  Node -->  Node --> Node --> Node --> Node --> Node --> Node --> Node

    Node (K Key, V Value, Node next)
    Index(Node node, Index down, Index right)  纵向上，所有Index的node都是最底层那个
    HeadIndex extends Index，就是多个属性 level
     */
    private static void ConcurrentSkipListMap() {
        ConcurrentSkipListMap map = new ConcurrentSkipListMap();
        for (int i = 10; i > 0; i--) {
            map.put(i, i);
        }
        System.out.println(map);
    }

    // 看看Queue能不能放Null，结论：所有的Queue都不能放Null！
    private static void testQueueHasNull() {
        List<Queue> list = Arrays.asList(
                new PriorityQueue(),
                new ConcurrentLinkedQueue(),
                new SynchronousQueue(),
                new ArrayBlockingQueue(10),
                new LinkedBlockingQueue(),
                new PriorityBlockingQueue(),
                new DelayQueue(),
                new LinkedTransferQueue(),
                new ArrayDeque(),
                new ConcurrentLinkedDeque(),
                new LinkedBlockingDeque());
        for (Queue queue : list) {
            try {
                queue.add(null);
                System.out.printf("%s 可以放null\n", queue.getClass().getName());
            } catch (NullPointerException e) {
                System.out.printf("%s 不可以null\n", queue.getClass().getName());
            }
        }
    }

    /*
    SynchronousQueue  线程安全，“手递手”管道，不存数据
    两个构造函数：
    1、无参，默认非公平模式  2、boolean fair，可以选择是否用公平模式
    放：offer() offer(timeout)   非阻塞，有取的true，没取的false
    取：poll() 没有消息则返null    take() 没有消息则阻塞
     */
    private static void testSynchronousQueue() throws InterruptedException {
        int threadNum = 3;
        final SynchronousQueue queue = new SynchronousQueue();
        ExecutorService se = Executors.newFixedThreadPool(threadNum);
        for (int i = 0; i < threadNum; i++)
            se.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        System.out.printf("%s starts.\n", Thread.currentThread().getName());
//                    System.out.printf("%s get %s\n", Thread.currentThread().getName(), queue.poll());
                        System.out.printf("%s get %s\n", Thread.currentThread().getName(), queue.offer(111, 1, TimeUnit.SECONDS));
//                        System.out.printf("%s get %s\n", Thread.currentThread().getName(), queue.take());
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    System.out.printf("%s finish.\n", Thread.currentThread().getName());
                }
            });
        TimeUnit.SECONDS.sleep(1);
        queue.take();
    }

    /*
    ArrayBlockingQueue
     */
    private static void testArrayBlockingQueue() {
        int capacity = 32;
        Queue queue = new ArrayBlockingQueue(capacity);

    }

    /*
    Collections 集合工具类
    1、排序   2、查找、替换  3、同步（建议用JUC包下的 java.util.concurrent）
     */
    private static void testCollections() {
        List list = Arrays.asList(5, 4, 3, 2, 1, 9, 8, 7, 6);
        System.out.printf("init：%s\n", list);
        Collections.reverse(list); // 反转
        System.out.printf("reverse：%s\n", list);
        Collections.sort(list); // 升序
        System.out.printf("sort：%s\n", list);
        Collections.swap(list, 1, 2); // 交换位置
        System.out.printf("swap：%s\n", list);
        Collections.rotate(list, 5); // 旋转(整体移位)，前(后)N个元素挪到前面(后面)，正负数不同
        System.out.printf("rotate：%s\n", list);
        int offset = Collections.binarySearch(list, 3); // 二分，必须有序，找不到-1
        System.out.printf("rotate：%d\n", offset);
        int max = (int) Collections.max(list); // 最大
        System.out.printf("max：%d\n", max);
//        Collections.fill(list, 1); // 填充
//        System.out.printf("fill：%s\n", list);
        int count = Collections.frequency(list, 2);
        System.out.printf("frequency：%d\n", count);
    }

    public static void main(String[] args) throws InterruptedException {
        System.out.println("aaa");
    }
}
